package com.warmheart.core.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ObjUtil {

    private static final Logger LOG = LoggerFactory.getLogger(ObjUtil.class);

    private ObjUtil() {
    }

    public static List<BasicNameValuePair> getNvps(Object obj) {
        List<BasicNameValuePair> result = new ArrayList<BasicNameValuePair>();
        if (null == obj) {
            return result;
        }

        Field[] fields = getFields(obj);
        for (int i = 0; i < fields.length; i++) {
            String filedName = fields[i].getName();

            // value只能是简单对象
            Object fieldValueObj = getFieldValueByName(filedName, obj);
            String fieldValue = (null == fieldValueObj || StringUtils.isBlank(fieldValueObj.toString())) ? ""
                    : fieldValueObj.toString();
            BasicNameValuePair pair = new BasicNameValuePair(filedName, fieldValue);
            result.add(pair);
        }

        return result;
    }

    public static Map<String, Object> obj2map(Object obj) {
        if (null == obj) {
            return new HashMap<String, Object>();
        }

        Field[] fields = getFields(obj);

        Map<String, Object> result = new HashMap<String, Object>();

        for (int i = 0; i < fields.length; i++) {
            result.put(fields[i].getName(), getFieldValueByName(fields[i].getName(), obj));
        }

        return result;
    }

    /**
     * object转换成treeMap，如果值为空，该值不会在map中返回
     * 
     * @param obj
     * @return
     */
    public static TreeMap<String, Object> obj2TreemapExcludeEmpty(Object obj) {
        TreeMap<String, Object> result = new TreeMap<String, Object>();

        if (null == obj) {
            return result;
        }

        Field[] fields = getFields(obj);

        for (int i = 0; i < fields.length; i++) {
            Object value = getFieldValueByName(fields[i].getName(), obj);

            if (null == value || StringUtils.isBlank(value.toString())) {
                continue;
            }

            result.put(fields[i].getName(), value);
        }

        return result;
    }

    private static Object getFieldValueByName(String fieldName, Object obj) {
        String firstLetter = fieldName.substring(0, 1).toUpperCase();
        try {
            String getter = "get" + firstLetter + fieldName.substring(1);
            Method method = obj.getClass().getMethod(getter, new Class[] {});
            Object value = method.invoke(obj, new Object[] {});

            return value;
        } catch (NoSuchMethodException e) {
            // 如果是方法未找到，可能变量是boolean类型，用is重新尝试一把
            try {
                String getter = "is" + firstLetter + fieldName.substring(1);
                Method method = obj.getClass().getMethod(getter, new Class[] {});
                Object value = method.invoke(obj, new Object[] {});

                return value;
            } catch (Exception e1) {
                LOG.error("ObjUtil.getFieldValueByName error, obj=[" + obj + "],fieldName=[" + fieldName + "]", e);
                throw new RuntimeException("ObjUtil.getFieldValueByName error，fieldName=" + fieldName);
            }
        } catch (Exception e) {
            LOG.error("ObjUtil.getFieldValueByName error, obj=[" + obj + "],fieldName=[" + fieldName + "]", e);
            throw new RuntimeException("ObjUtil.getFieldValueByName error");
        }
    }

    private static Field[] getFields(Object obj) {
        Class<?> cls = obj.getClass();

        List<Field[]> result = new ArrayList<Field[]>();
        Field[] fs = cls.getDeclaredFields();

        do {
            result.add(fs);
            cls = cls.getSuperclass();
            fs = cls.getDeclaredFields();
        } while (null != fs && fs.length > 0);

        int size = 0;
        for (int i = 0; i < result.size(); i++) {
            size += result.get(i).length;
        }

        Field[] ret = new Field[size];
        int index = 0;
        for (int i = 0; i < result.size(); i++) {
            for (int j = 0; j < result.get(i).length; j++) {
                ret[index++] = result.get(i)[j];
            }
        }

        return ret;
    }
}